Loading...
 

Query - The syntax of a query string

The syntax of a query string:

Query_Expression ::=
Boolean_Expression | Compare_Expression | Quoted_Expression | Bracket_Expression | Exist_Expression | Nested_Expression | Boolean_Constant
Boolean_Expression ::= (Query_Epression'|' Query_Expression) | (Query_Expression'&' Query_Expression)
Compare_Expression ::= Statement Operator Statement
Quoted_Expression ::=
# [Ascii(32)...Ascii(34), Ascii(36)...Ascii(127)]* #
Nested_Expression ::=
[!] Path ([: Query_Expression :] | [% Query_Expression %])
Exist_Expression ::=
[!]?Path
Bracket_Expression ::=
[!] ( Query_Expression )
Statement ::= Path | Placeholder | Constant
Operator ::= | >= | <= | < | > | != | @ | !@ | <> | >< | ~
Path ::= Identifier.Path | Identifier->Path | Identifier
Placeholder ::= %{ s | h | i | N | V | D | T | P | F | S | O | STRING | HASH_STRING | INTEGER | Classname}
Constant ::= Boolean_Constant | String_Constant | Numeric_Constant | Classname | Null_Constant
Identifier ::= Member_Identifier | Method_Identifier
Member_Identifier ::=
[&][::] a..Z [a..Z | 0..9]*
Method_Identifier ::=
a..Z [a..Z | 0..9]* ()
Classname ::= CX_NUMERIC | CX_VALUE | CX_DATE | CX_SPAN_DATE. .
Boolean_Constant ::= true | false
Numeric_Constant ::= Integer_Constant | Real_Constant | Value_Constant
Null_Constant ::= NULL
Integer_Constant ::= 0..9 0..9*
Real_Constant ::= Integer_Constant . Integer_Constant
Value_Constant ::= (Real_Constant | Integer_Constant) Unit
Unit - one of the units defined in the ClassiX® system -

semantics:

  • For variable values taken from the stack, placeholders must appear in the query string:
    or for Example
    %s
    %STRING a string
    "000001" "uniqueID = %s" FindFirst(CX_CUSTOMER)
    %h
    %HASH_STRINGa hash string
    %i
    %INTEGER an integer value
    1 "settings= %i" FindFirst(CX_CUSTOMER)
    %N %CX_NUMERIC CX_NUMERIC
    %V %CX_VALUE CX_VALUE
    %D %CX_DATE CX_DATE
    %T %CX_TIME CX_TIME
    %P %CX_PERCENT CX_PERCENT
    %F %CX_FRACTION CX_FRACTION
    %S %CX_SPAN_DATE CX_SPAN_DATE
    %O %CX_CLASS one object
    %Class name - one object "partner @ %CX_CORPORATION" FindFirst(CX_CUSTOMER)
  • The placeholders are replaced with the values from the stack in sequence from left to right. The first placeholder from the left is replaced with the top value (Top) of the stack, the second with the second top value, and so on.
    From

    "a""b" "c""x = %s & y = %s & z = %s" Find(...)

    would therefore

    "x = \"c\" & y = \"b\" & z = \"a\"

    can be formed.
    As a mnemonic, draw a horizontal line in your thoughts between the last parameter and the query string, which symbolises a mirror. The placeholder closest to the mirror on the right side corresponds to the parameter on the left side, which is also closest to the mirror. Then move away from the mirror on the right side (to the right) to the next placeholder, and on the left side move away from the mirror (to the left) to the next parameter:

    "a""b""c" | "x = %s & y = %s & z = %s" Find(...)
    (| is the mirror)
  • For a priori known values constants can be written:
    Type Example
    Character string "name = \"Worthing\"
    numerical constant "number = 2.1828"
    Value constant "credit > $25000.00"
    ID of a class "classID = CX_ITEM_CAST"
    However, placeholders have an advantage: If a query with the same structure but different values (e.g. with placeholders) is executed several times, then intermediate objects of the query are cached with the InstantView query string and can be retrieved more quickly when called repeatedly.
    suchString "uniqueID = %s" Find(CX_ITEM)
    is therefore often called up with different search strings faster than:
    "uniqueID = \"" suchString + "\"" + Find(CX_ITEM)

  • Data fields of the objects are designated by their name - this also applies to dynamic data fields.
  • If a field name is used twice, i.e. the same name designates both a data member of a class and a dynamic data field known in the ClassiX® system, the name in the query expression always refers to the dynamic data field. To refer to the "fixed" data member, the name must be preceded by a scope operator: ::fieldname.
  • Functions of an object can only be called if they have been logged in as query function in the ClassiX® system. This is only possible for parameterless functions.
  • An InstantView® access expression can be specified in the query string with the pseudo-function Retrieve. This eliminates many of the restrictions mentioned above; e.g. any functions can be called with parameters, even those that return transient data.
  • Indexes can be created to speed up queries (index manager)
  • The query manager in the ClassiX® system manages all queries executed with Find, FindFirst or FindExists.
  • Queries can generally only be started using collections of classes that are derived from the type CX_EXPANDABLE.
  • Mit collection[:queryExpression:] können nested queries definiert werden. ObjectStore muss den Typ der Objekte in der Collection kennen. Ein dafür nötiger Cast - (osSet<Klasse> &) - wird vom Query-Manager automatisch konstruiert, wenn dort das Tupel (Collectionname, Elementtyp) angemeldet wurde.
  • A @ in front of a data field or slot means that not the content of the object is to be viewed, but the address. This is especially useful for indexes, e.g. if a fixed data field of type CX_ITEM_PATTERN is to be indexed: The object itself cannot be indexed, but its address can. This speeds up the search for a specific pattern ("pattern @ %CX_ITEM_PATTERN" Find(CX_ITEM)).
  • Indexes on an address cannot be sorted.
  • With the question mark operator (?) you can check whether a slot exists or not. For example, "?comment" finds all objects whose comment slot exists. It is irrelevant whether a value is ultimately stored in it or not (an empty string in the case of strings). With ! the expression can be negated: "!?comment" would find all objects whose comment slot does NOT exist.
    For constructions such as "?father.father", the existence of the slot "father of father" or "grandfather" is checked, i.e. only the last slot of the expression is checked for existence.
  • With the operator ~ character strings can be compared with the help of patterns. (QM module: Queries with Pattern Matching)

    Example: "name ~ \"A*\"" finds all objects whose attribute 'name' begins with a capital A. Regular expressions cannot be used in the patterns!

    The following rules apply: A * (asterisk) stands for any number of characters, whereby the number can also be 0. So "house" would match the pattern "H*out". A ? (question mark) stands for exactly 1 arbitrary character. * and ? can be combined with each other in any combination and can also occur several times. If you want to search for the ? or * character, you must precede it with a \. For example, to search for everything that starts with "Auto*Star", "Auto\*Star*" is the correct query string. The same applies to the backslash itself.

    A special feature is the expression \i, e.g. for "name ~ \"\ia*\"". \i causes the comparison of the character strings to be carried out without regard to upper/lower case. In the last example, all objects would be found whose attribute 'name' begins with a capital or small A. \i may only be located at the beginning of the pattern.

    The expression to be compared with the pattern is always to the left of the operator ~, the pattern always to the right of it. The left side can be a constant, a placeholder, a fixed or indexed data field or the Retrieve() function. The right side may only contain a constant or a placeholder. Data fields are not supported at this point. If these rules are not followed, ObjectStore will complain about the error in the query expression.

    The comparison with samples is provided by ObjectStore, not by the ClassiX® system. This means that indexes are also used for queries. Pattern comparisons of the type "ABC*" are therefore carried out particularly efficiently, as the index can be used for comparisons of this type.
  • ClassiX keeps queries in a cache and remembers ObjectStore-relevant calculated information for the next access. This accelerates the phase from query creation to its execution. Query strings with pattern matching have a peculiarity in that pattern matching with placeholders at this point offers hardly any performance gain compared to the use of constants, because the query has to be translated differently for optimisation depending on the concrete value of the search string. Only the parsing of the query string itself is not necessary.
    "Ad*" "uniqueID ~ %s" Find(CX_ITEM)
    is therefore practically equivalent to
    "uniqueID ~ \"Ad*\"" Find(CX_ITEM)
  • If a desired query does not work due to the query translation performed by ClassiX, there is a way out via the Quoted_Expression. Here, all characters between the "#" characters are passed to the query mechanism of ObjectStore without translation.

Attention!
As soon as a collection contains "wrapped" objects of this class in addition to objects of a specific class X, no query can be formulated that refers to fixed data fields and/or query functions of class X.
Queries that only refer to dynamic data fields also work in this case.

Attention:
If a query is executed via a CX_VALUE slot, then it must be noted that the query will fail if a value with a concrete unit (example: 2m) is searched for and the objects in the searched collection contain incompatible units (example: 1$). In this case, the query can only be performed using the numerical value by searching with the unit ? (Ex: 2?).

- Examples -